import test from './test';
import { round } from './digit';

/**
 * 如果value小于min，取min；如果value大于max，取max
 */
function range(min: number = 0, max: number = 0, value: number = 0): number {
  return Math.max(min, Math.min(max, Number(value)));
}

/**
 * 用于获取用户传递值的px值
 */
export function getPx(value: number | string, unit: boolean = false): number | string {
  if (test.number(value)) {
    return unit ? `${value}px` : Number(value);
  }

  if (/(rpx|upx)$/.test(value)) {
    return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)));
  }

  return unit ? `${parseInt(value)}px` : parseInt(value);
}

/**
 * 进行延时，以达到可以简写代码的目的
 */
export function sleep(value: number = 30): Promise<void> {
  return new Promise<void>((resolve) => {
    setTimeout(() => {
      resolve();
    }, value);
  });
}

/**
 * 运行期判断平台
 */
export function os(): string {
  return uni.getSystemInfoSync().platform.toLowerCase();
}

/**
 * 获取系统信息同步接口
 */
export function sys(): any {
  return uni.getSystemInfoSync();
}

/**
 * 取一个区间数
 */
function random(min: number, max: number): number {
  if (min >= 0 && max > 0 && max >= min) {
    const gab = max - min + 1;
    return Math.floor(Math.random() * gab + min);
  }
  return 0;
}

/**
 * 生成UUID
 */
export function guid(len: number = 32, firstU: boolean = true, radix: number | null = null): string {
  const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  const uuid: string[] = [];
  radix = radix || chars.length;

  if (len) {
    for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
  } else {
    let r;
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
    uuid[14] = '4';

    for (let i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | (Math.random() * 16);
        uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
      }
    }
  }

  if (firstU) {
    uuid.shift();
    return `u${uuid.join('')}`;
  }
  return uuid.join('');
}

/**
 * 获取父组件的参数
 */
export function $parent(name: string | undefined = undefined): any {
  let parent = this.$parent;
  while (parent) {
    if (parent.$options && parent.$options.name !== name) {
      parent = parent.$parent;
    } else {
      return parent;
    }
  }
  return false;
}

/**
 * 样式转换
 */
export function addStyle(customStyle: object | string, target: string = 'object'): object | string {
  if (
    test.empty(customStyle) ||
    (typeof customStyle === 'object' && target === 'object') ||
    (target === 'string' && typeof customStyle === 'string')
  ) {
    return customStyle;
  }

  if (target === 'object') {
    customStyle = trim(customStyle);
    const styleArray = customStyle.split(';');
    const style: any = {};
    for (let i = 0; i < styleArray.length; i++) {
      if (styleArray[i]) {
        const item = styleArray[i].split(':');
        style[trim(item[0])] = trim(item[1]);
      }
    }
    return style;
  }

  let string = '';
  for (const i in customStyle) {
    const key = i.replace(/([A-Z])/g, '-$1').toLowerCase();
    string += `${key}:${customStyle[i]};`;
  }
  return trim(string);
}

/**
 * 添加单位
 */
export function addUnit(value: string | number = 'auto', unit: string = 'px'): string | number {
  value = String(value);
  return test.number(value) ? `${value}${unit}` : value;
}

/**
 * 深度克隆
 */
function deepClone(obj: any): any {
  if ([null, undefined, NaN, false].includes(obj)) return obj;
  if (typeof obj !== 'object' && typeof obj !== 'function') {
    return obj;
  }
  const o = test.array(obj) ? [] : {};
  for (const i in obj) {
    if (obj.hasOwnProperty(i)) {
      o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
    }
  }
  return o;
}

/**
 * JS对象深度合并
 */
export function deepMerge(target: object = {}, source: object = {}): object | boolean {
  target = deepClone(target);
  if (typeof target !== 'object' || typeof source !== 'object') return false;
  for (const prop in source) {
    if (!source.hasOwnProperty(prop)) continue;
    if (prop in target) {
      if (typeof target[prop] !== 'object') {
        target[prop] = source[prop];
      } else if (typeof source[prop] !== 'object') {
        target[prop] = source[prop];
      } else if (target[prop].concat && source[prop].concat) {
        target[prop] = target[prop].concat(source[prop]);
      } else {
        target[prop] = deepMerge(target[prop], source[prop]);
      }
    } else {
      target[prop] = source[prop];
    }
  }
  return target;
}

/**
 * error提示
 */
function error(err: any): void {
  if (process.env.NODE_ENV === 'development') {
    console.error(`SheepJS:${err}`);
  }
}

/**
 * 打乱数组
 */
function randomArray(array: any[] = []): any[] {
  return array.sort(() => Math.random() - 0.5);
}

// padStart 的 polyfill
if (!String.prototype.padStart) {
  String.prototype.padStart = function (maxLength: number, fillString: string = ' '): string {
    if (Object.prototype.toString.call(fillString) !== '[object String]') {
      throw new TypeError('fillString must be String');
    }
    const str = this;
    if (str.length >= maxLength) return String(str);

    const fillLength = maxLength - str.length;
    let times = Math.ceil(fillLength / fillString.length);
    while ((times >>= 1)) {
      fillString += fillString;
      if (times === 1) {
        fillString += fillString;
      }
    }
    return fillString.slice(0, fillLength) + str;
  };
}

/**
 * 时间格式化
 */
export function timeFormat(dateTime: number | string = 0, formatStr: string = 'yyyy-MM-dd HH:mm:ss'): string {
  dateTime = new Date(dateTime);
  const formatObj: any = {
    y: dateTime.getFullYear(),
    M: dateTime.getMonth() + 1,
    d: dateTime.getDate(),
    H: dateTime.getHours(),
    m: dateTime.getMinutes(),
    s: dateTime.getSeconds(),
    S: dateTime.getMilliseconds(),
  };
  return formatStr.replace(/([yMdhmsS])+/g, (result: string, key: string): string => {
    let value = formatObj[key];
    if (key === 'y') {
      value = String(value).substr(4 - RegExp.$1.length);
    } else if (key === 'S') {
      value = `000${value}`.substr(String(value).length);
    }
    return value && result.length > 1 ? value : `0${value}`.substr(String(value).length);
  });
}

/**
 * 时间差格式化
 */
export function timeFrom(timestamp: number | string = 0, format: string = 'yyyy-MM-dd HH:mm:ss'): string {
  const dateTime = new Date(timestamp).getTime();
  const now = Date.now();
  let differ = (now - dateTime) / 1000;

  const result = ['秒', '分钟', '小时', '天', '月', '年'];
  const len = [60, 3600, 86400, 2592000, 31104000];
  for (let i = 5; i >= 0; i--) {
    if (differ >= len[i]) {
      return timeFormat(dateTime, format);
    }
    differ = i > 0 ? differ / len[i - 1] : differ;
    if (differ < 1) return `${Math.round(differ * 60)}${result[i - 1]}前`;
    return `${Math.round(differ)}${result[i - 1]}前`;
  }
}

/**
 * 去空格
 */
export function trim(str: string, pos: string = 'all'): string {
  if (!test.string(str)) return str;
  switch (pos) {
    case 'left':
      return str.replace(/(^\s*)/g, '');
    case 'right':
      return str.replace(/(\s*$)/g, '');
    default:
      return str.replace(/\s+/g, '');
  }
}

/**
 * 将对象转换为url参数
 */
export function queryParams(data: object = {}, isPrefix: boolean = false, arrayFormat: string = 'brackets'): string {
  let prefix = isPrefix ? '?' : '';
  let _result: any = [];
  for (const key in data) {
    const value = data[key];
    if (value === undefined) {
      continue;
    }
    _result.push(`${key}=${encodeURIComponent(value)}`);
  }

  let result = _result.join('&');
  if (arrayFormat === 'brackets') {
    result = result.replace(/%20/g, '+');
  }
  return prefix + result;
}

/**
 * toast提示
 */
export function toast(title: string = '', duration: number = 2000): void {
  uni.showToast({
    title,
    icon: 'none',
    duration,
  });
}

/**
 * 类型对应图标
 */
export function type2icon(type: string = '', fill: boolean = false): string {
  const icon = {
    folder: 'folder',
    image: 'picture',
    video: 'video',
    audio: 'voice',
    txt: 'document',
    word: 'doc',
    excel: 'excel',
    ppt: 'ppt',
    pdf: 'pdf',
  };
  return fill ? `icon-${icon[type]}` : icon[type];
}

/**
 * 金额格式化
 */
export function priceFormat(
  number: number | string = 0,
  decimals: number = 2,
  decimalPoint: string = '.',
  thousandsSeparator: string = ',',
): string {
  number = (number + '').replace(/[^0-9+-Ee.]/g, '');
  const n = !isFinite(+number) ? 0 : +number;
  const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
  const sep = thousandsSeparator;
  const dec = decimalPoint;
  let s = '';

  const toFixedFix = function (n: number, prec: number): string {
    const k = Math.pow(10, prec);
    return '' + Math.round(n * k) / k;
  };

  s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
  const re = /(-?\d+)(\d{3})/;
  while (re.test(s[0])) {
    s[0] = s[0].replace(re, '$1' + sep + '$2');
  }

  if ((s[1] || '').length < prec) {
    s[1] = s[1] || '';
    s[1] += new Array(prec - s[1].length + 1).join('0');
  }
  return s.join(dec);
}

/**
 * 时间持续时间
 */
export function getDuration(value: number = 0, unit: string = 'ms'): number {
  if (unit === 'ms') return value;
  if (unit === 's') return value * 1000;
  if (unit === 'm') return value * 1000 * 60;
  if (unit === 'h') return value * 1000 * 3600;
  return 0;
}

/**
 * 数字补零
 */
export function padZero(value: number | string = 0): string {
  return `${value}`.padStart(2, '0');
}

/**
 * 获取对象属性
 */
export function getProperty(obj: any, key: string = ''): any {
  if (!obj || typeof obj !== 'object' || !key) return undefined;
  const keys = key.split('.');
  let result = obj;
  for (let i = 0; i < keys.length; i++) {
    if (result && result.hasOwnProperty(keys[i])) {
      result = result[keys[i]];
    } else {
      return undefined;
    }
  }
  return result;
}

/**
 * 设置对象属性
 */
export function setProperty(obj: any, key: string = '', value: any): void {
  if (!obj || typeof obj !== 'object' || !key) return;
  const keys = key.split('.');
  let target = obj;
  for (let i = 0; i < keys.length - 1; i++) {
    if (!target[keys[i]]) {
      target[keys[i]] = {};
    }
    target = target[keys[i]];
  }
  target[keys[keys.length - 1]] = value;
}

/**
 * 获取当前页面路径
 */
export function page(): string {
  const pages = getCurrentPages();
  return pages.length ? pages[pages.length - 1].route : '';
}

/**
 * 获取当前页面参数
 */
export function params(): any {
  const pages = getCurrentPages();
  return pages.length ? pages[pages.length - 1].options : {};
}

/**
 * 返回上一页
 */
export function back(delta: number = 1): void {
  uni.navigateBack({ delta });
}

/**
 * 获取当前页面实例
 */
export function current(): any {
  const pages = getCurrentPages();
  return pages.length ? pages[pages.length - 1] : {};
}

/**
 * 创建一个WebSocket
 */
export function ws(url: string = '', options: object = {}): WebSocket {
  return new WebSocket(url, options);
}

/**
 * 对象转换为FormData
 */
export function toFormData(data: any): FormData {
  const formData = new FormData();
  Object.keys(data).forEach((key) => {
    formData.append(key, data[key]);
  });
  return formData;
}

/**
 * 数字取整
 */
export function int(number: number = 0): number {
  return Math.floor(Number(number));
}

/**
 * 字符串转为大写
 */
export function upper(str: string = ''): string {
  return str.toUpperCase();
}

/**
 * 字符串转为小写
 */
export function lower(str: string = ''): string {
  return str.toLowerCase();
}

/**
 * 判断两个对象是否相等
 */
export function isEqual(obj1: any, obj2: any): boolean {
  return JSON.stringify(obj1) === JSON.stringify(obj2);
}

/**
 * 获取本地存储的数据
 */
export function storageGet(key: string = ''): any {
  return uni.getStorageSync(key);
}

/**
 * 设置本地存储的数据
 */
export function storageSet(key: string = '', data: any): void {
  uni.setStorageSync(key, data);
}

/**
 * 移除本地存储的数据
 */
export function storageRemove(key: string = ''): void {
  uni.removeStorageSync(key);
}

/**
 * 清空本地存储的数据
 */
export function storageClear(): void {
  uni.clearStorageSync();
}

/**
 * 倒计时
 */
export function countdown(endTime: number = 0, serverTime: number = Date.now()): string {
  let result = '';
  const time = Math.max(endTime - serverTime, 0);
  const day = Math.floor(time / (1000 * 60 * 60 * 24));
  const hour = Math.floor((time / (1000 * 60 * 60)) % 24);
  const minute = Math.floor((time / (1000 * 60)) % 60);
  const second = Math.floor((time / 1000) % 60);
  if (day > 0) result += `${day}天`;
  if (hour > 0) result += `${hour}小时`;
  if (minute > 0) result += `${minute}分`;
  if (second > 0) result += `${second}秒`;
  return result;
}

/**
 * 获取元素距离页面顶部的距离
 */
export function getElementTop(element: HTMLElement | null): number {
  let actualTop = element ? element.offsetTop : 0;
  let current = element ? element.offsetParent as HTMLElement : null;
  while (current) {
    actualTop += current.offsetTop;
    current = current.offsetParent as HTMLElement;
  }
  return actualTop;
}

/**
 * 获取页面滚动的距离
 */
export function getPageScrollTop(): number {
  return document.documentElement.scrollTop || document.body.scrollTop;
}

/**
 * 设置页面滚动的距离
 */
export function setPageScrollTop(value: number): void {
  document.documentElement.scrollTop = value;
  document.body.scrollTop = value;
}

/**
 * 滚动到指定元素
 */
export function scrollToElement(element: HTMLElement | null, duration: number = 300): void {
  if (!element) return;
  const from = getPageScrollTop();
  const to = getElementTop(element);
  const distance = Math.abs(from - to);
  const frames = Math.ceil((duration * 1000) / 60);
  let count = 0;
  const step = (to - from) / frames;
  function animate() {
    setPageScrollTop(from + step * count++);
    if (count < frames) {
      requestAnimationFrame(animate);
    }
  }
  animate();
}

/**
 * 数字千分位分隔符
 */
export function formatNumber(value: number | string = 0): string {
  return String(value).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
}

/**
 * 对象转换为查询字符串
 */
export function objectToQueryString(obj: any): string {
  return Object.keys(obj)
    .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
    .join('&');
}

/**
 * 下载文件
 */
export function downloadFile(url: string = '', fileName: string = ''): void {
  uni.downloadFile({
    url,
    success: (res) => {
      uni.saveFile({
        tempFilePath: res.tempFilePath,
        success: (saveRes) => {
          uni.showToast({
            title: '下载成功',
            icon: 'success',
          });
          if (fileName) {
            uni.saveFile({
              tempFilePath: res.tempFilePath,
              filePath: `${uni.env.USER_DATA_PATH}/${fileName}`,
            });
          }
        },
        fail: () => {
          uni.showToast({
            title: '保存失败',
            icon: 'none',
          });
        },
      });
    },
    fail: () => {
      uni.showToast({
        title: '下载失败',
        icon: 'none',
      });
    },
  });
}

/**
 * 检测网络状态
 */
export function getNetworkType(): Promise<string> {
  return new Promise((resolve, reject) => {
    uni.getNetworkType({
      success: (res) => {
        resolve(res.networkType);
      },
      fail: () => {
        reject('获取网络状态失败');
      },
    });
  });
}

/**
 * 保留小数点后n位
 */
export function decimal(value: number | string = 0, precision: number = 2): string {
  return round(Number(value), precision).toFixed(precision);
}

/**
 * 数组分页
 */
export function paginate(array: any[] = [], size: number = 10): any[] {
  return array.reduce((acc, val, i) => {
    const idx = Math.floor(i / size);
    const page = acc[idx] || (acc[idx] = []);
    page.push(val);
    return acc;
  }, []);
}

/**
 * 防抖函数
 */
export function debounce(func: Function, wait: number = 300): Function {
  let timeout: any;
  return function (...args: any[]) {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(this, args);
    }, wait);
  };
}

/**
 * 节流函数
 */
export function throttle(func: Function, wait: number = 300): Function {
  let previous = 0;
  return function (...args: any[]) {
    const now = Date.now();
    if (now - previous > wait) {
      func.apply(this, args);
      previous = now;
    }
  };
}

/**
 * 获取当前页面栈数组
 */
export function pages(): UniApp.Page.Instance[] {
  return getCurrentPages();
}

/**
 * 复制文本到剪贴板
 */
export function copyText(text: string): void {
  uni.setClipboardData({
    data: text,
    success: () => {
      uni.showToast({
        title: '复制成功',
        icon: 'success',
      });
    },
    fail: () => {
      uni.showToast({
        title: '复制失败',
        icon: 'none',
      });
    },
  });
}

/**
 * 获取根域名
 */
export function getRootUrl(url: string): string {
  return url.split('/')[2];
}
